package com.sniff.atp.service.check;

import com.alibaba.fastjson.TypeReference;
import com.sniff.atp.dto.ClientLoginDTO;
import com.sniff.atp.dto.order.CustomerPlatformOrderItemRespDTO;
import com.sniff.atp.dto.order.GetPlatformOrderDetailRespDTO;
import com.sniff.atp.dto.settlement.CustomerWalletFundFlowRespDTO;
import com.sniff.atp.enums.settlement.FundFlowTypeEnum;
import com.sniff.atp.enums.status.*;
import com.sniff.atp.service.order.OrderService;
import com.sniff.atp.service.settlement.SettlementService;
import com.sniff.atp.utils.FastUtil;
import com.sniff.atp.utils.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.testng.Assert;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class SettlementCheck {
    @Autowired
    private OrderService orderService;
    @Autowired
    private SettlementService settlementService;

    public void fundFlowCheck(ClientLoginDTO clientLoginDTO, String platformOrderNo, OrderOperateFund operateFund) {
        String orderDetail = orderService.clientOrderDetail(clientLoginDTO, platformOrderNo);
        GetPlatformOrderDetailRespDTO platformOrderDetail = FastUtil.toBean(JsonUtil.extractJSONObject(orderDetail, "data"), GetPlatformOrderDetailRespDTO.class);
        List<CustomerPlatformOrderItemRespDTO> platformOrderItemList = platformOrderDetail.getPlatformOrderItemList();
        String fundFlow = settlementService.queryFundFlow(clientLoginDTO, platformOrderNo);
        List<CustomerWalletFundFlowRespDTO> fundFlows = FastUtil.toBean(JsonUtil.extractJSONArray(fundFlow, "data.records"), new TypeReference<List<CustomerWalletFundFlowRespDTO>>() {
        });
        productCheck(platformOrderItemList, fundFlows, operateFund, clientLoginDTO);
    }

    private void productCheck(List<CustomerPlatformOrderItemRespDTO> orderItemList, List<CustomerWalletFundFlowRespDTO> fundFlows, OrderOperateFund operateFund, ClientLoginDTO clientLoginDTO) {
        if (operateFund.equals(OrderOperateFund.order_finish)) {
            BigDecimal orderPrice = new BigDecimal("0.00");
            for (CustomerPlatformOrderItemRespDTO orderItem : orderItemList) {
                orderPrice = orderPrice.add(orderItem.getActualTotalProductSellPrice());
            }
            CustomerWalletFundFlowRespDTO fundFlowRespDTO = fundFlows.stream().filter(fundFlow -> fundFlow.getFundFlowNameCustomer().equals(FundFlowTypeEnum.AMOUNT_FREEZE.getJpName()))
                    .findFirst().orElse(new CustomerWalletFundFlowRespDTO());
            BigDecimal fundPrice = fundFlowRespDTO.getChangeAmount();
            Assert.assertEquals(orderPrice, fundPrice, OrderOperateFund.order_finish.getName() + "-流水校验-金额校验");
        }
        if (operateFund.equals(OrderOperateFund.purchase_finish_B2B)) {
            purchaseChargeCheck(orderItemList, fundFlows, operateFund, clientLoginDTO);
        }
        if (operateFund.equals(OrderOperateFund.purchase_finish_D2C)) {
            purchaseChargeCheck(orderItemList, fundFlows, operateFund, clientLoginDTO);
        }
    }

    private void purchaseChargeCheck(List<CustomerPlatformOrderItemRespDTO> orderItemList, List<CustomerWalletFundFlowRespDTO> fundFlows, OrderOperateFund operateFund, ClientLoginDTO clientLoginDTO) {
        List<BigDecimal> fundExpress = new ArrayList<>();
        List<BigDecimal> fundCharges = new ArrayList<>();
        fundFlows.forEach(fundFlow -> {
            if (fundFlow.getFundFlowNameCustomer().equals(FundFlowTypeEnum.EXPRESS_AMOUNT.getJpName())) {
                fundExpress.add(fundFlow.getChangeAmount());
            }
            if (FundFlowTypeEnum.getPurchaseJpName().contains(fundFlow.getFundFlowNameCustomer())) {
                fundCharges.add(fundFlow.getChangeAmount());
            }
        });
        List<BigDecimal> expectExpress = new ArrayList<>();
        List<BigDecimal> expectCharges = new ArrayList<>();
        orderItemList.forEach(orderItem -> {
            if (clientLoginDTO.getSystemSource().equals(SystemType.B2B.getType())) {
                orderProductB2B(orderItem, expectExpress, expectCharges);
                if (orderItem.getProductType().equals(ProductType.COMB.getType())) {
                    orderItem.getCombinationOrderItemList().forEach(item -> orderProductB2B(item, expectExpress, expectCharges));
                }
            } else {
                orderProductD2C(orderItem, expectExpress, expectCharges);
            }

        });
        fundCheckout(fundExpress, expectExpress, operateFund.getName() + "-运费-金额校验");
        fundCheckout(fundCharges, expectCharges, operateFund.getName() + "-手续费-金额校验");
    }

    private void orderProductB2B(CustomerPlatformOrderItemRespDTO orderItem, List<BigDecimal> expectExpress, List<BigDecimal> expectCharges) {
        if (orderItem.getProductType().equals(ProductType.OEM.getType())) {
            expectExpress.add(new BigDecimal(AdditionConfig.EXPRESS_OEM.getCost()));
            expectCharges.add(AdditionConfig.getCost(AdditionConfig.OEM_B2B).multiply(orderItem.getActualProductSellPrice()).multiply(new BigDecimal(orderItem.getSellQuantity())));
        }
        if (orderItem.getProductType().equals(ProductType.NORMAL.getType())) {
            if (orderItem.getChannel().equals(ChannelType.CLEAR.getType())) {
                expectExpress.add(AdditionConfig.getCost(AdditionConfig.EXPRESS_CLEAR));
                expectCharges.add(AdditionConfig.getCost(AdditionConfig.CLEAR_B2B).multiply(orderItem.getActualProductSellPrice()).multiply(new BigDecimal(orderItem.getSellQuantity())));
            } else {
                expectCharges.add(AdditionConfig.getCost(AdditionConfig.MARKET_B2B).multiply(new BigDecimal(orderItem.getSellQuantity())));
            }
        }
    }

    private void orderProductD2C(CustomerPlatformOrderItemRespDTO orderItem, List<BigDecimal> expectExpress, List<BigDecimal> expectCharges) {
        if (orderItem.getProductType().equals(ProductType.OEM.getType())) {
            expectExpress.add(new BigDecimal(AdditionConfig.EXPRESS_OEM.getCost()));
            expectCharges.add(AdditionConfig.getCost(AdditionConfig.OEM_D2C).multiply(orderItem.getActualProductSellPrice()).multiply(new BigDecimal(orderItem.getSellQuantity())));
        }
        if (orderItem.getProductType().equals(ProductType.NORMAL.getType())) {
            if (orderItem.getChannel().equals(ChannelType.CLEAR.getType())) {
                expectExpress.add(AdditionConfig.getCost(AdditionConfig.EXPRESS_CLEAR));
                expectCharges.add(AdditionConfig.getCost(AdditionConfig.CLEAR_D2C).multiply(orderItem.getActualProductSellPrice()).multiply(new BigDecimal(orderItem.getSellQuantity())));
            } else {
                expectCharges.add(AdditionConfig.getCost(AdditionConfig.MARKET_D2C).multiply(new BigDecimal(orderItem.getSellQuantity())));
            }
        }
    }

    private void fundCheckout(List<BigDecimal> actual, List<BigDecimal> expect, String message) {
        actual = actual.stream().map(item -> item.setScale(2, RoundingMode.HALF_UP)).sorted().collect(Collectors.toList());
        expect = expect.stream().map(item -> item.setScale(2, RoundingMode.HALF_UP)).sorted().collect(Collectors.toList());
        Assert.assertEquals(actual, expect, message);
    }

}
